use crate::utils::{RwLinkedList, RwNode};
use anyhow::Result;
use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;
use std::sync::atomic::AtomicU64;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::sync::RwLock;
use uuid::Uuid;

/// 键值对结构体
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct KeyValPair<K, V>
where
    K: Eq + PartialEq + Hash,
    V: Eq + PartialEq,
{
    pub key: Arc<K>,
    pub val: Arc<V>,
    ttl: u64,       // 存活时间戳，单位是秒
    time_key: u128, // 存活时间戳，单位是毫秒
}

impl<K, V> KeyValPair<K, V>
where
    K: Eq + Hash + PartialEq,
    V: Eq + PartialEq,
{
    /// ttl是存活时间，单位是秒
    pub fn new_now(key: Arc<K>, val: V, ttl: u64) -> KeyValPair<K, V> {
        KeyValPair {
            key,
            val: Arc::new(val),
            ttl: now_sec() + ttl,
            time_key: (ttl * 1000) as u128 + now_millis(),
        }
    }

    /// 更新
    pub fn update_now(&mut self, ttl: u64) {
        self.ttl = now_sec() + ttl;
        self.time_key = (ttl * 1000) as u128 + now_millis();
    }
}

/// 具有超时控制的HashMap<br/>
/// 每个内容物的超时时间是一样的<br/>
/// 插入已有的key相当于重置超时时间
#[derive(Debug)]
pub struct TimeoutMap<K, V>
where
    K: Hash + Eq + PartialEq,
    V: PartialEq + Eq,
{
    ttl: u64,                // 键值对存活时间，单位是秒
    last_cleanup: AtomicU64, // 上一次清理键值对的时间戳
    list: RwLinkedList<KeyValPair<K, V>>,
    map: HashMap<Arc<K>, RwNode<KeyValPair<K, V>>>,
}

impl<K: Eq + Hash + PartialEq, V: PartialEq + Eq> TimeoutMap<K, V> {
    fn new(secs: u64) -> RwLock<TimeoutMap<K, V>> {
        RwLock::new(TimeoutMap {
            ttl: secs,
            last_cleanup: AtomicU64::new(now_sec()),
            list: RwLinkedList {
                head: None,
                tail: None,
                len: 0,
                uuid: Uuid::now_v7(),
            },
            map: HashMap::new(),
        })
    }

    async fn put(&mut self, key: K, val: V) -> Result<()> {
        let arc_key = Arc::new(key);
        // 判断键值对是否已经插入
        if self.map.contains_key(&arc_key) {
            // 已经插入，更新过期时间
            let n = self.map.get_mut(&arc_key).unwrap();
            self.list.move_tail(n).await?;
            let mut ref_n = n.write().await;
            ref_n.data.update_now(self.ttl);
        } else {
            // 没有插入，插入即可
            let kv = KeyValPair::new_now(arc_key.clone(), val, self.ttl);
            let n = self.list.push_tail(kv).await?;
            self.map.insert(arc_key, n);
        }
        Ok(())
    }

    async fn get(&self, key: &K) -> Result<Option<RwNode<KeyValPair<K, V>>>, String> {
        let r = self.map.get(key);
        if let Some(n) = r {
            return Ok(Some(n.clone()));
        }
        Ok(None)
    }
}

/// 获取秒级时间戳
pub fn now_sec() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs()
}

/// 获取毫秒级时间戳
pub fn now_millis() -> u128 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_millis()
}

#[tokio::test]
async fn test() {
    let m = TimeoutMap::<i32, i32>::new(1800);
    m.write().await.put(1, 1).await.unwrap();
    m.write().await.put(2, 2).await.unwrap();

    let a = m.read().await.get(&2).await.unwrap();
    if let Some(n) = a {
        println!("get: {:?}", n.read().await.data);
    } else {
        println!("not found");
    }
}
